﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Vibz.Common.Channel;
using System.IO;
using System.Xml;
using Vibz.Common;
using System.IO.Pipes;
using Vibz.Common.Model;
using System.Text.RegularExpressions;

namespace Vibz.Server
{
    class Program
    {
        static StreamWriter sw;
        static NamedPipeClientStream pipeClient;
        static IModelManager manager = null;
        static void Main(string[] args)
        {
            try
            {
                string type = "";
                string path = "";
                string name = "";
                if (args.Length >= 1)
                    type = args[0];
                else
                {
                    while (string.IsNullOrEmpty(type))
                    {
                        Console.WriteLine("Enter model source details:");
                        type = Console.ReadLine();
                    }
                }

                switch (type.ToLower())
                {
                    case "xml":
                        if (args.Length >= 2)
                            path = args[1];
                        else
                        {
                            while (string.IsNullOrEmpty(path))
                            {
                                Console.WriteLine("Enter Xml path:");
                                path = Console.ReadLine();
                            }
                        }

                        if (args.Length >= 3)
                            name = args[2];
                        else
                        {
                            while (string.IsNullOrEmpty(name))
                            {
                                Console.WriteLine("Enter model name:");
                                name = Console.ReadLine();
                            }
                        }
                        XmlModelSource xModelSource = new XmlModelSource(path);
                        manager = xModelSource.GetModelManager(name);
                        break;
                }
                if (manager == null)
                    throw new Exception("No valid model manager found");

                ServerManager sMgr = new ServerManager(name, manager);
                string connPath = sMgr.Init();
                Console.WriteLine("Server is started at " + connPath);

                if (args.Length >= 4 && args[3].ToLower() == "c")
                {
                    Console.WriteLine("Running controlled mode.");

                    pipeClient = new NamedPipeClientStream(".", name, PipeDirection.InOut, PipeOptions.Asynchronous);

                    if (!pipeClient.IsConnected)
                    {
                        pipeClient.Connect();
                        //sw.AutoFlush = true;
                        Console.WriteLine("Messaging service connected.");
                    }

                    sw = new StreamWriter(pipeClient);

                    try
                    {
                        SendMessage("Server for Model '" + name + "' is initialized and is waiting for Clients to connect.", false);
                        SendMessage(connPath, true);
                        // Listen to controller
                        string command = "";
                        StreamReader sr = new StreamReader(pipeClient);
                        while (true)
                        {
                            try
                            {
                                command = sr.ReadLine();
                                if (string.IsNullOrEmpty(command))
                                {
                                    continue;
                                }
                                Console.WriteLine("Command recieved from controller - " + command);
                                switch (command.ToLower())
                                {
                                    case "start":
                                        sMgr.Start();
                                        //SendMessage("Server has been started for Model '" + name + "'.", true);
                                        break;
                                    case "save":
                                        sMgr.Save();
                                        //SendMessage("Model '" + name + "' is saved.", true);
                                        break;
                                    case "stop":
                                        //SendMessage("Server for Model '" + name + "' is shutting down.", true);
                                        Console.Read();
                                        return;
                                }
                            }
                            catch (Exception exc)
                            {
                                throw new Exception("Unhandled exception while listening on pipe. ", exc);
                            }
                        }
                    }
                    catch (Exception exc)
                    {
                        throw new Exception("Could not initializing Model server manager. ", exc);
                    }    
                    return;
                }
                
                Console.WriteLine("Running isolated mode.");
                while (true)
                {
                    sMgr.Start();
                    Console.Read();
                }
            }
            catch (SystemException ex)
            {
                Exception tempExc = ex;
                string message = tempExc.Message;
                while (tempExc.InnerException != null)
                {
                    message += "\r\n" + tempExc.InnerException.Message;
                    tempExc = tempExc.InnerException;
                }
                Console.WriteLine("System error occured: " + message + "\r\n" + ex.StackTrace);
                SendMessage("System error occured: " + ex.Message, true);
                Console.ReadLine();
            }
            catch (Exception exc)
            {
                Exception tempExc = exc;
                string message = tempExc.Message;
                while (tempExc.InnerException != null)
                {
                    message += "\r\n" + tempExc.InnerException.Message + "\r\n" + tempExc.InnerException.StackTrace;
                    tempExc = tempExc.InnerException;
                }
                Console.WriteLine("Error occured: " + message + "\r\n" + exc.StackTrace);
                SendMessage("Error occured: " + exc.Message, true);
                Console.ReadLine();
            }
        }
        static void SendMessage(string message, bool sendToServer)
        {
            if (sendToServer && sw != null && pipeClient.IsConnected)
            {
                sw.WriteLine(message);
                sw.Flush();
                pipeClient.WaitForPipeDrain();
            }
        }
    }
}